package com.livepan.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Component
public class LoginGatewayFilter implements GatewayFilter, Ordered {
    private static final Logger LOG = LoggerFactory.getLogger(LoginGatewayFilter.class);

    private static final ArrayList<String> NO_LOGIN_URLS = new ArrayList<>();

    static {
        NO_LOGIN_URLS.add("/system/kaptcha");
        NO_LOGIN_URLS.add("/problem/list");
        NO_LOGIN_URLS.add("/contest/list");
        NO_LOGIN_URLS.add("/system/user/logout");
        NO_LOGIN_URLS.add("/system/user/login");
        NO_LOGIN_URLS.add("/contest/getList");
        NO_LOGIN_URLS.add("/submission/getList");
        NO_LOGIN_URLS.add("/business/category/all");
        NO_LOGIN_URLS.add("/system/user/profile");
        NO_LOGIN_URLS.add("/system/user/register");

    }

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        LOG.info("gateway进行拦截");
        String path = exchange.getRequest().getURI().getPath();

        // 请求地址中不包含/admin/的，不是控台请求，不需要拦截
        if (NO_LOGIN_URLS.contains(path)) {
            LOG.info("不需要控台登录验证：{}", path);
            return chain.filter(exchange);
        }

        //获取cookie的token参数
        List<HttpCookie> cookies = exchange.getRequest().getCookies().get("token");
        if (cookies == null || cookies.size() == 0 || cookies.get(0).getValue().isEmpty()) {
            LOG.info("token为空，请求被拦截");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String token = cookies.get(0).getValue();
        LOG.info("控台登录验证开始，token：{}", token);
        Object object = redisTemplate.opsForValue().get(token);
        if (object == null) {
            LOG.warn("token无效，请求被拦截");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        } else {
            LOG.info("已登录：{}", object);

            // 增加权限校验，gateway里没有LoginUserDto，所以全部用JSON操作
            LOG.info("接口权限校验，请求地址：{}", path);
            boolean exist = false;
            JSONObject loginUserDto = JSON.parseObject(String.valueOf(object));
            LOG.info(loginUserDto.toString());
            JSONArray requestList = loginUserDto.getJSONArray("requestList");
            // 遍历所有【权限请求】，判断当前请求的地址是否在【权限请求】里
            for (int i = 0, l = requestList.size(); i < l; i++) {
                String request = (String) requestList.get(i);
                if (path.contains(request)) {
                    exist = true;
                    break;
                } else {
                    LOG.info(request);
                    LOG.info(path);
                }
            }
            if (exist) {
                LOG.info("权限校验通过");
            } else {
                LOG.warn("权限校验未通过");
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
